package com.juc.threadpool;

import sun.misc.Unsafe;


import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

/**
 * fixed thread pool test
 *
 * @author mobai
 * @since 2021/3/1 14:59
 */
public class FixedThreadPoolTest {

    // 演示OOM
    static class Task implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(1500000000000000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public static void main(String[] args) throws InterruptedException {
//        Calc calc = new Calc();
//        CountDownLatch countDownLatch = new CountDownLatch(4);
//        calc.setCountDownLatch(countDownLatch);
//        ExecutorService executorService = Executors.newFixedThreadPool(4);
//        for (int i = 0; i < 4; i++) {
//            executorService.execute(calc::run);
//        }
//        countDownLatch.await();
//        System.out.println(calc.value);
//        executorService.shutdownNow();

        Ticket ticket = new Ticket();
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 4; i++) {
            executorService.execute(ticket);
        }
        executorService.shutdown();

    }

    static class Ticket implements Runnable {

        private volatile int ticket = 100;

        private static final long valueOffSet;

        static {
            try {
                valueOffSet = Calc.THE_UNSAFE.objectFieldOffset(Ticket.class.getDeclaredField("ticket"));
            } catch (NoSuchFieldException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void run() {
            do {
                int old = Calc.THE_UNSAFE.getIntVolatile(this, valueOffSet);
                if (old > 0 && Calc.THE_UNSAFE.compareAndSwapInt(this, valueOffSet, old, old - 1)) {
                    System.out.println("线程" + Thread.currentThread().getName() + "抢到票,当前剩余" + (old - 1));
                }
            } while (Calc.THE_UNSAFE.getIntVolatile(this, valueOffSet) > 0);
        }
    }


    /**
     * 线程安全的自增运算器
     */
    public static class Calc {

        public volatile int value = 0;


        private static final long valueOfSet;

        public static final Unsafe THE_UNSAFE;

        static {
            try {
                final PrivilegedExceptionAction<Unsafe> action = () -> {
                    Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                    theUnsafe.setAccessible(true);
                    return (Unsafe) theUnsafe.get(null);
                };
                THE_UNSAFE = AccessController.doPrivileged(action);
                valueOfSet = THE_UNSAFE.objectFieldOffset(Calc.class.getDeclaredField("value"));
            } catch (Exception e) {
                throw new RuntimeException("Unable to load unsafe", e);
            }
        }


        private CountDownLatch countDownLatch;

        public void setCountDownLatch(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        public void run() {
            for (int i = 0; i < 1000; i++) {
                int var5;
                do {
                    var5 = THE_UNSAFE.getIntVolatile(this, valueOfSet);
                } while (!THE_UNSAFE.compareAndSwapInt(this, valueOfSet, var5, var5 + 1));

            }
            countDownLatch.countDown();

        }

    }
}
